package com.boot2.core;

import com.alibaba.fastjson.annotation.JSONField;
import com.boot2.core.constant.CoreConstant;
import com.boot2.core.model.dto.CommonBaseEntity;
import com.boot2.core.web.RequestContext;
import com.fasterxml.jackson.annotation.JsonIgnore;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.apache.commons.lang3.reflect.MethodUtils;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import javax.persistence.Column;
import javax.persistence.EntityListeners;
import javax.persistence.MappedSuperclass;
import javax.persistence.Transient;
import javax.servlet.http.HttpSession;
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.util.Date;

/**
 * @author zhangweilin
 * @ClassName: BaseEntity
 * @description: model 基类,兼容mysql,mongo等持久层
 * @date 2017年12月18日 下午2:01:54
 */
@Data
@EntityListeners({AuditingEntityListener.class, JpaBaseEntityAuditListener.class})
@MappedSuperclass
// @JsonIgnoreProperties({ "ids" }) // 指定ids不序列化
public class BaseEntity extends CommonBaseEntity {

    /**
     *
     */
    private static final long serialVersionUID = 1L;

    /**
     * 创建时间
     */
    @CreatedDate
    @ApiModelProperty(hidden = true)
    @Column(columnDefinition = "datetime")
//    @Column(columnDefinition = "timestamp")
    protected Date createTime;
//
    /**
     * 创建时间,查询时的左区间, 10.
     * 建议，区间查询,请注意，凡是有区间查询的操作，在po或vo中命名时，左边界约定一律为原属性名+1,右边界为+2,比如查询年龄范围，有原属性为age,则左边界为age1,右边界为age2
     */
    @Transient // 一般情况不序列化
    @JsonIgnore // jackson不序列化
    @JSONField(serialize = false) // fast不序列化
    @ApiModelProperty(hidden = true)
    protected Date createTime1;

    /**
     * 创建时间,查询时的右区间
     */
    @Transient // 一般情况不序列化
    @JsonIgnore // jackson不序列化
    @JSONField(serialize = false) // fast不序列化
    @ApiModelProperty(hidden = true)
    protected Date createTime2;

    /**
     * 更新时间
     */
    @LastModifiedDate
    @ApiModelProperty(hidden = true)
    @Column(columnDefinition = "datetime")
//    @Column(columnDefinition = "timestamp")
    protected Date updateTime;

    /**
     * 创建者用户ID
     */
    @ApiModelProperty(hidden = true)
    protected Long createrId;

    /**
     * 创建者名称
     */
    @ApiModelProperty(hidden = true)
    @Column(length = 30)
    protected String createrName;

    /**
     * 更新者用户id
     */
    @ApiModelProperty(hidden = true)
    protected Long updaterId;

    /**
     * 更新者名称
     */
    @ApiModelProperty(hidden = true)
    @Column(length = 30)
    protected String updaterName;

//    /** 请求参数 */
//    @Transient // 一般情况不序列化
//    @JsonIgnore // jackson不序列化
//    @JSONField(serialize = false) // fast不序列化
//    @ApiModelProperty(hidden = true)
//    private Map<String, Object> params;

    /**
     * 是否删除,@Transient，使mongo中就不存在此字段，但是jpa也不会生成语句
     */
    // @Transient // 一般情况不序列化
    @JsonIgnore // jackson不序列化
    @JSONField(serialize = false) // fast不序列化
    @ApiModelProperty(hidden = true)
    @Column(columnDefinition = "bigint default 0 not null")
    protected Boolean isDeleted = false;

    /**
     * 默认的空实现，不初始化信息，一般由框架反射构造时调用
     */
    public BaseEntity() {

    }

    /**
     * 非空实现。在业务代码中手动调用,用来初始化一些基础信息
     */
    public BaseEntity(boolean isInit) {
        if (isInit) {
            initBaseData();
        }
    }

    /**
     * 初始化基础信息,这个只为手动调用，千万不要自动调用
     */
    public void initBaseData() {
        this.createTime = new Date();

        HttpSession session = RequestContext.getSession();
        if (null == session) {
            return;
        }
        String loginSessionKey = (String) session.getAttribute(CoreConstant.loginSessionKey);

        // 这样兼容了多个登录体系
        Object user = session.getAttribute(loginSessionKey);
        if (user == null) {
            return;
        }
        String userName;
        try {
            userName = (String) MethodUtils.invokeMethod(user, "getUserName"); // 在设计登录表时，请按规约约定，用户名一律为userName
            this.createrName = userName;
        } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    /**
     * 此方法特殊， 返回加密后的id,加密方式采用AES+Base64,因为加密的key为
     * 所有者userName+当前类名（首字母小写）+约定密钥常量组成，故如果未登录调用此方法,直接抛异常 要保证此字段不被任何框架序列化
     *
     * @return
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     * @throws NoSuchMethodException
     */
//    @Transient // 一般情况不序列化
//    @JsonIgnore // jackson不序列化
//    @JSONField(serialize = false) // fast不序列化
//    @ApiModelProperty(hidden = true)
//    public String getIds() {
//        HttpSession session = RequestContext.getSession();
//        if (null == session) {
//            return String.valueOf(this.getId());
//        }
//        Object customer = session.getAttribute(CoreConstant.customerLoginSessionKey);
//        if (customer == null) {
////			throw new LoginException("尚未登录，禁止访问");
//            return "";
//        }
//        // 所有者userName+当前类名（全小写）+约定密钥常量,故同一个用户。看同一个实体时，其加密后的id也不一样，这样保证与身份绑定起来，好校验
//        String userName;
//        try {
//            userName = (String) MethodUtils.invokeMethod(customer, "getUserName");
//
//            String key = userName + "_" + StringUtils.changFirstWord(this.getClass().getSimpleName(), StringUtils.toLowerCase) + "_" + UrlProperties.aesEncryptKey;
//            String ids = AesUtil.aesEncodeWithBase64(key, getId() + "");
//            return ids;
//        } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
//            // TODO Auto-generated catch block
//            e.printStackTrace();
//        }
//        return "";
//    }

    /**
     * 获取加密后的id
     *
     * @param propertiesName
     * @param value
     * @return
     */
//    public String getAesId(String propertiesName, String value) {
//        Object customer = RequestContext.getSession().getAttribute(CoreConstant.customerLoginSessionKey);
//        if (customer == null) {
////			throw new LoginException("尚未登录，禁止访问");
//            return "";
//        }
//
//        String modelName = this.getClass().getSimpleName();
//
//        // 所有者userName+当前类名（全小写）+约定密钥常量,故同一个用户。看同一个实体时，其加密后的id也不一样，这样保证与身份绑定起来，好校验
//        String userName;
//        try {
//            userName = (String) MethodUtils.invokeMethod(customer, "getUserName");
//
//            if ("id".equals(propertiesName.toLowerCase()) || "parentId".equals(propertiesName)) {
//                // modelName为自身
//            } else if (propertiesName.matches(".*[iI][dD]")) {
//                modelName = propertiesName.replaceAll("[iI][dD]", "");
//            }
//
//            String key = userName + "_" + StringUtils.changFirstWord(modelName, StringUtils.toLowerCase) + "_" + UrlProperties.aesEncryptKey;
//            String ids = AesUtil.aesEncodeWithBase64(key, value);
//            return ids;
//        } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
//            // TODO Auto-generated catch block
//            e.printStackTrace();
//        }
//        return "";
//    }


    public Serializable getId() {
        return null;
    }

    /**
     * 默认设置当前时间为创建时间
     */
    public void setCreateTime() {
        //只有为空时才new,否则为更新
        if (this.getCreateTime() == null) {
            this.setCreateTime(new Date());
        }
    }
}
